﻿// 237. 程序自动分析.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <unordered_map>


using namespace std;

/*
https://www.acwing.com/problem/content/239/

在实现程序自动分析的过程中，常常需要判定一些约束条件是否能被同时满足。

考虑一个约束满足问题的简化版本：假设 x1,x2,x3,… 代表程序中出现的变量，给定 n 个形如 xi=xj 或 xi≠xj 的变量相等/不等的约束条件，
请判定是否可以分别为每一个变量赋予恰当的值，使得上述所有约束条件同时被满足。

例如，一个问题中的约束条件为：x1=x2，x2=x3，x3=x4，x1≠x4，这些约束条件显然是不可能同时被满足的，因此这个问题应判定为不可被满足。

现在给出一些约束满足问题，请分别对它们进行判定。

输入格式
输入文件的第 1 行包含 1 个正整数 t，表示需要判定的问题个数，注意这些问题之间是相互独立的。

对于每个问题，包含若干行：

第 1 行包含 1 个正整数 n，表示该问题中需要被满足的约束条件个数。

接下来 n 行，每行包括 3 个整数 i,j,e，描述 1 个相等/不等的约束条件，相邻整数之间用单个空格隔开。若 e=1，则该约束条件为 xi=xj；若 e=0，则该约束条件为 xi≠xj。

输出格式
输出文件包括 t 行。

输出文件的第 k 行输出一个字符串 YES 或者 NO，YES 表示输入中的第 k 个问题判定为可以被满足，NO 表示不可被满足。

数据范围
1≤n≤105
1≤i,j≤109
输入样例：
2
2
1 2 1
1 2 0
2
1 2 1
2 1 1
输出样例：
NO
YES
*/

const int N = 100010 * 2;
int p[N];
unordered_map<int, int> mm; int idx;
int j, n;

int queryIdx;
struct QUERY {
	int a; int b;
}query_no_equal[N];



void init() {
	for (int i = 0; i < N; i++) { p[i] = i; }
}

int get(int x) {
	if (mm.count(x) != 0) { return mm[x]; }
	else { mm[x] = ++idx; return idx; }
}

int find(int x) {
	if (x != p[x]) { p[x] = find(p[x]); }
	return p[x];
}

void merge(int a, int b) {
	a = find(a); b = find(b);
	p[a] = b;
}

int main()
{
	cin >> j;

	while (j--) {
		init();
		cin >> n;
		int success = 1;  queryIdx = 0; idx = 0; mm.clear();
		for (int i = 0; i < n; i++) {
			int a, b, op;
			cin >> a >> b >> op;
			a = get(a); b = get(b);
			if (op == 1) {
				merge(a, b);
			}
			else {
				query_no_equal[queryIdx] = { a,b }; queryIdx++;
			}
		}

		for (int i = 0; i < queryIdx; i++) {
			int a = query_no_equal[i].a; int b = query_no_equal[i].b;
			if (find(a) == find(b)) {
				success = 0; break;
			}
		}

		if (success) {
			cout << "YES" << endl;
		}
		else {
			cout << "NO" << endl;
		}
	}


	return 0;
}